package signx

import (
	"codeup.aliyun.com/lsxd/zltx/adapter/utils/formater"
	"codeup.aliyun.com/lsxd/zltx/adapter/utils/signx/hash"
)

// SignFunc 签名函数
type SignFunc func(data, key string, opts ...string) ([]byte, error)

// Option 签名/验证选项
type Option func(*options)

// WithData 待签名数据
func WithData(data string) Option {
	return func(o *options) {
		o.data = data
	}
}

// WithKey 签名密钥
func WithKey(key string) Option {
	return func(o *options) {
		o.key = key
	}
}

// WithArgs 其他参数，如盐值等
func WithArgs(args ...string) Option {
	return func(o *options) {
		o.args = append(o.args, args...)
	}
}

// WithSignFn 签名函数
func WithSignFn(fn SignFunc) Option {
	return func(o *options) {
		o.signFn = fn
	}
}

// WithFormatFn 签名格式化函数
func WithFormatFn(fn formater.Formater) Option {
	return func(o *options) {
		o.formatFn = fn
	}
}

// WithSigned 待验证的签名值（验证时需要）
func WithSigned(signed string) Option {
	return func(o *options) {
		o.signed = signed
	}
}

// WithVerifyFn 验证函数（验证规则不同于签名函数时需要）
func WithVerifyFn(fn VerifyFunc) Option {
	return func(o *options) {
		o.verifyFn = fn
	}
}

// options 签名选项
type options struct {
	data     string            // 待签名数据
	key      string            // 签名密钥
	args     []string          // 其他参数，如盐值等
	signFn   SignFunc          // 签名函数，第一个参数为待签名数据，第二个参数为签名密钥，第三个参数为盐值，其他参数可选
	formatFn formater.Formater // 签名格式 (hex/hex_upper/hex_lower/base64)
	signed   string            // 待验证的签名值
	verifyFn VerifyFunc        // 验证函数，第一个参数为待签名数据，第二个参数为签名值，第三个参数为签名密钥，其他参数可选
}

func defaultSignOptions() *options {
	return &options{
		signFn:   hash.Md5,
		formatFn: formater.HexLower,
	}
}

// Sign 签名
func Sign(opts ...Option) (string, error) {
	opt := defaultSignOptions()
	for _, o := range opts {
		o(opt)
	}

	// 签名
	sign, err := opt.signFn(opt.data, opt.key, opt.args...)
	if err != nil {
		return "", err
	}

	// 格式化
	return opt.formatFn.Encode(sign), nil
}
